#!/bin/sh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# r51a.hsc src/hsc/scripts/restore.sh 1.11 
#  
# Licensed Materials - Property of IBM 
#  
# Restricted Materials of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2001,2003 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 

#-------------------------------------------------------------------------------
# restore.sh
# 
# This shell script is invoked to perform a restore of the HSC backup data.
# This script should be executed every time the system reboots.  If no
# "indicator" file is present, the script exits and no file restoration is done.
# 
# Usage: 'restore'
#
# Return Codes:
# 1 - Error mounting the upgrade partition
# 2 - Error Copying from the media
# 3 - Archive not present
# 4 - Error unmounting the media
# 5 - Other Errors
# 6 - DVD drive failure
# 7 - No media inserted
# 8 - Unformatted media
# 9 - Incorrect label on media
# 10 - tar error extracting relative to working directory
# 11 - unable to create staging directory
# 12 - no need to run a restore
# 13 - unable to generate the excluded shared object file list
# 14 - tar error extracting non-*.so files relative to / dir
# 15 - staged file move/copy error

#-------------------------------------------------------------------------------
# directory and filename which records the backup actions.
#-------------------------------------------------------------------------------
LOGDIR=/var/hsc/log
LOG=$LOGDIR/restore.log

LOG_ERROR_LOG=/tmp/restore.log
ARCHIVE_LOG=/tmp/archive.log

# stdout of 'mount' command directed to /tmp/mount_output+PID
MOUNT_OUTPUT=/tmp/mount_output$$

#-------------------------------------------------------------------------------
# mount point: the mount point where the backup data is contained
#-------------------------------------------------------------------------------
MOUNTPOINT=/mnt/cdrom

#-------------------------------------------------------------------------------
# the filename of the backup archive
#-------------------------------------------------------------------------------
ARCHIVENAME=backuphdr.tgz
ARCHIVE=$MOUNTPOINT/$ARCHIVENAME

#-------------------------------------------------------------------------------
# the (hard drive) media mount point where the indicator file, created by the
# CD re-install process, is stored.  There should be an entry for this
# mountpoint in /etc/fstab.  Also set the Linux kernel mount point location
#-------------------------------------------------------------------------------
UPGRADE_MOUNTPOINT=/mnt/upgrade
DOS_MOUNTPOINT=/mnt/dos

#-------------------------------------------------------------------------------
# the indicator file. If it exists, execute 'tar' cmd to restore the backup data
#-------------------------------------------------------------------------------
INDFILE=iqybcrit.dat
IQYBCRIT=$UPGRADE_MOUNTPOINT/$INDFILE

#-------------------------------------------------------------------------------
# Flag to indicate a critical error has occurred during 'tar' file processing
#-------------------------------------------------------------------------------
ARCHIVEFAIL=0

#-------------------------------------------------------------------------------
# Flags/variables used for error processing
#-------------------------------------------------------------------------------
let CP_INDICATOR=0
let MV_INDICATOR=0

 
#
# common exit point for script
#
exit_cleanup() {
    rm -f $MOUNT_OUTPUT
    umount $UPGRADE_MOUNTPOINT
    umount $DOS_MOUNTPOINT
    
    if [ $ARCHIVEFAIL -ne 0 ]; then
         echo "!potential critical archive failure!" >> $LOG
         echo "archive failure error code is: $ARCHIVEFAIL" >> $LOG
         echo "task completed on `date`, return status = 99" >> $LOG
         exit 99
    else
         echo "task completed on `date`, return status = $1" >> $LOG
    fi
    exit $1
}  



# Check if the directory for the log file exists.
if [ ! -d $LOGDIR ]; then
     echo "=================================================================" > $LOG_ERROR_LOG
     echo -e "Restore task log for `date`." >> $LOG_ERROR_LOG
     echo "Restore task log directory, <$LOGDIR>, does not exist. Program exiting" >> $LOG_ERROR_LOG
     exit 5
fi


# Just in case we have NLS troubles reading system information...
LANG=en_US
export LANG


# Start log to record restore actions.
if [ -f $LOG ]; then
     mv $LOG $LOG.1
fi
echo -e "Restore log for `date`\n" > $LOG


#-------------------------------------------------------------------------------
# Mount the media where the indicator file should be located
#-------------------------------------------------------------------------------
mount -v $UPGRADE_MOUNTPOINT > $MOUNT_OUTPUT 2>&1
if [ $? -ne 0 ]; then

   #----------------------------------------------------------------------------
   # already mounted?  Not an error, but a non-zero return code.  Continue
   #----------------------------------------------------------------------------
   if grep "already mounted" $MOUNT_OUTPUT; then
        echo "The mountpoint, $UPGRADE_MOUNTPOINT, is already mounted.  Continuing..." >> $LOG

   #----------------------------------------------------------------------------
   # other error?  Game over.
   #----------------------------------------------------------------------------
   else
        echo "The mountpoint, $UPGRADE_MOUNTPOINT, cannot be mounted.  Error is $?" >> $LOG
        exit_cleanup 1
   fi
fi

#-------------------------------------------------------------------------------
# good mount of output device, continue
#-------------------------------------------------------------------------------
echo "partition with indicator file, $INDFILE, mounted at $UPGRADE_MOUNTPOINT." >> $LOG


#-------------------------------------------------------------------------------
# if IQYBCRIT.DAT doesn't exist, there is nothing to do
#-------------------------------------------------------------------------------
if [ ! -e $IQYBCRIT ]; then
      echo "$IQYBCRIT indicator file does not exist. Data restoration not required" >> $LOG
      echo -e "restore script exiting.\n" >> $LOG
      exit_cleanup 12
fi


#-------------------------------------------------------------------------------
# Check to see if the backup media (DVD) is already mounted
#-------------------------------------------------------------------------------
if grep -q "$MOUNTPOINT" /etc/mtab; then
      # Media is already mounted, unmount in preparation for (re-)'mount' cmd
     if ! umount -v $MOUNTPOINT >> $LOG 2>&1; then
          echo "Couldn't umount the media... exiting" >> $LOG
          exit_cleanup 4
     fi
fi

#-------------------------------------------------------------------------------
# Mount and check for existence of archive
#-------------------------------------------------------------------------------
#if mount -t udf -v $MOUNTPOINT > $MOUNT_OUTPUT 2>&1; then   # udf/dvd specific
if mount -v $MOUNTPOINT > $MOUNT_OUTPUT 2>&1; then
     echo "successfully mounted the backup media, continuing..." >> $LOG

# leave this test out since HSC does not do a specific DVD format
#       if !(chkudf /dev/hdc | grep -q -i "ACTBKP" 2>&1); then # udf/dvd specific
     false=0
     if false; then # floppy test
          echo "The media has an incorrect label... exiting" >> $LOG
          umount $MOUNTPOINT
          exit_cleanup 9
     elif [ ! -e $ARCHIVE ]; then
          echo "The backup archive is not on the restore media... exiting" >> $LOG
          umount $MOUNTPOINT
          exit_cleanup 3
     fi
     echo "backup archive file detected on media, continuing..." >> $LOG
else
     echo "Could NOT mount the media..." >> $LOG

     # Check for no media inserted. If this is the case, we're going to remove the
     # iqybcrit.dat file.  That file should never remain on the system unless the
     # product recovery CD was just used. The last thing the recovery CD process
     # does is prompt to insert the backup archive media.  Hence, if no media, no
     # need for recovery indicator flag.
     #
     # Using 'grep' here seems kinda unnecessary/risky. We should just key off
     # 'mount' cmd return codes instead...

     if grep -q -i "wrong major or minor number" $MOUNT_OUTPUT; then
          echo -e "Hardware failure on the DVD RAM drive... exiting\n" >> $LOG
          exit_cleanup 6
     elif grep -q -i "No medium found" $MOUNT_OUTPUT; then
          echo -e "No media in the DVD RAM drive... exiting\n" >> $LOG

          # Here's one place where we'll remove the indicator file. This
          # will hopefully catch the manufacturing process issue whereby
          # they are installing the pHMCs from the recovery CD, which
          # contains the indicator file, during the initial HMC install.
          # That file should not initially be on the system.  The 'no media'
          # return code from 'mount' cmd is 32.
          rm -f $IQYBCRIT

          exit_cleanup 7
     elif grep -q -i "wrong fs type" $MOUNT_OUTPUT; then
          echo -e "Wrong filesystem type, or unformatted media, or wrong media type... exiting\n" >> $LOG
          exit_cleanup 8
     else
          echo -e "Unknown error... exiting\n" >> $LOG
          exit_cleanup 5
     fi
fi

# If the file hmcConfigured exists then
# it is not a new install, the DVD containing
# backup data happens to be inserted in
new_install=1
if [ -f /opt/hsc/data/hmcConfigured ]; then
     new_install=0
fi




#-------------------------------------------------------------------------------
# Now do the actual restore from the archive
#-------------------------------------------------------------------------------
echo -e "starting file archive restore...\n" >> $LOG

#
# Mount in case we're restoring kernel data
#
mount -v $DOS_MOUNTPOINT > $MOUNT_OUTPUT 2>&1
if [ $? -ne 0 ]; then

   #----------------------------------------------------------------------------
   # already mounted?  Not an error, but a non-zero return code.  Continue
   #----------------------------------------------------------------------------
   if grep "already mounted" $MOUNT_OUTPUT; then
        echo "The mountpoint, $DOS_MOUNTPOINT, is already mounted.  Continuing..." >> $LOG

   #----------------------------------------------------------------------------
   # other error?  Game over.
   #----------------------------------------------------------------------------
   else
        echo "The mountpoint, $DOS_MOUNTPOINT, cannot be mounted.  Error is $?" >> $LOG
        exit_cleanup 1
   fi
fi

#
# First thing to do is determine which files are shared objects that could 
# potentially be partially paged in the system.  Hence, a recurring read
# of that same library file could panic the system - in theory, of course.
# Rather than using the 'tar' command to restore those particular archive
# files, we'll be staging those files and using the 'mv' command.
#
# Construct a working/staging directory for pre/post processing 
#
WORKING_DIR=/tmp/restore/work
mkdir -p $WORKING_DIR
if [ $? -ne 0 ]; then
     umount -v $MOUNTPOINT >> $LOG 2>&1
     exit_cleanup 11
fi

#
# start with a clean error log
#
rm -f $ARCHIVE_LOG
echo -e "begin file recovery error log for `date`\n" > $ARCHIVE_LOG

#
# build the list of all files that have a '.so' "extension" (except the library
# file search path cache, 'ld.so.cache' )
#
tar -tvzf $ARCHIVE | grep "\.so" | grep -v "ld.so.cache" | awk '{print $6}' > $WORKING_DIR/exclude.list 2>> $ARCHIVE_LOG
if [ $? -ne 0 ]; then
     umount -v $MOUNTPOINT >> $LOG 2>&1
     exit_cleanup 13
fi

#
# Catch any kernel updates as well
#
tar -tvzf $ARCHIVE | grep "/mnt/dos" | awk '{print $6}' >> $WORKING_DIR/exclude.list 2>> $ARCHIVE_LOG

#
# Add the 'tar' command itself here. We'll restore file this with a cp/mv sequence
# when the 'tar' command has completed executing
#
tar -tvzf $ARCHIVE | grep "/bin/tar" | awk '{print $6}' >> $WORKING_DIR/exclude.list 2>> $ARCHIVE_LOG

echo "exclude file processing list constructed, continuing..." >> $LOG

#
# Next step is to un-tar only the previously excluded files to the
# staging area.
#
# Bypass the cache file containg references to the prior list of libraries
# residing in the directories listed in /etc/ld.so.conf.  We will dynamically
# regenerate this file using 'ldconfig' at end of 'tar'  processing
#
tar -xvzf $ARCHIVE --files-from=$WORKING_DIR/exclude.list --directory=$WORKING_DIR >> $ARCHIVE_LOG 2>&1
tarRC=$?
if [ $tarRC -ne 0 ]; then
     ARCHIVEFAIL=$tarRC
     echo "shared object 'tar' processing to working directory failed (rc = $tarRC). Continuing..." >> $LOG
else
     echo "'tar' processing of shared objects/misc files to working directory successful." >> $LOG
fi

#
# Now un-tar all remaining files from the archive, with a few exceptions
#
#echo "/opt/hsc/bin/restore" >> $WORKING_DIR/special.list
#echo "/etc/init.d/hmcRestore" >> $WORKING_DIR/special.list
echo "/var/hsc/log/restore.log" > $WORKING_DIR/special.list
echo "/var/hsc/log/restore.log.1" >> $WORKING_DIR/special.list
echo "/var/hsc/log/hmcRestore.log" >> $WORKING_DIR/special.list
echo "/tmp/archive.log" >> $WORKING_DIR/special.list

#
# Special case file - /sbin/srcmstr. That program gets run from inittab prior
# to this script on pHMC and 'tar' cmd returns "text file busy" msg, rc=2.
# If we find this file in the archive, then rename the "old"/current version
# so the 'tar' command will not return the warning error.  (Note: seems has
# to have something more to do with inodes/filesystem than the 'tar'
# program itself).
#
PHMC=0
tar -tvzf $ARCHIVE | grep "srcmstr" > /dev/null 2>&1
if [ $? -eq 0 ]; then
     PHMC=1
     rm -f /sbin/srcmstr
     
     tar -tvzf $ARCHIVE | grep "opt/hsc/bin/restore" > /dev/null 2>&1
     if [ $? -eq 0 ]; then
          rm -f /opt/hsc/bin/restore
     fi
     
     tar -tvzf $ARCHIVE | grep "etc/init.d/hmcRestore" > /dev/null 2>&1
     if [ $? -eq 0 ]; then
          rm -f /etc/init.d/hmcRestore
     fi
     
     echo "special file processing completed." >> $LOG
fi   

#
# Now do the un-tar of the majority of the archive file.
#
tar -xvzPf $ARCHIVE --overwrite --exclude-from=$WORKING_DIR/exclude.list --exclude-from=$WORKING_DIR/special.list >> $ARCHIVE_LOG 2>&1
tarRC=$?
if [ $tarRC -ne 0 ]; then
     ARCHIVEFAIL=$tarRC
     echo "remaining 'tar' archive processing failed (rc = $tarRC). Continuing..." >> $LOG
else
     echo "remaining 'tar' archive file processing completed successfully." >> $LOG
fi


#
# Flush memory to disk, just in case
#   
sync

#
# The theory is here that we should now be referncing the archived library
# shared objects. Do this so we don't reference a file that is about to be
# replaced.
#
export LD_LIBRARY_PATH=$WORKING_DIR/lib:$WORKING_DIR/usr/lib

#
# Assuming this far, all files have been restored from the archive BUT
# we have to (pseudo-atomically?) relocate the *.so files.  We do this
# by 1) 'cp' the archive file to the *same filesystem* as it's current
# existing, version, then 2) 'mv' archived version to current version
#
# example: if archive file is '/tmp/file1.ext'...
# 1) copy '/tmp/restore/work/tmp/file1.ext' to '/tmp/file1.ext.stage',
# 2) move 'tmp/file1.ext.stage' to '/tmp/file1.ext'
#
# Note: Many of the *.so files will most likely be symbolic links, so
#       be sure NOT to follow them when copying
#
for i in `cat $WORKING_DIR/exclude.list`
do
      d=`/usr/bin/dirname $i`
      mkdir -p $d
      cp -d -v $WORKING_DIR$i $i.stage >> $ARCHIVE_LOG 2>&1
      if [ $? -ne 0 ]; then
           let CP_INDICATOR=CP_INDICATOR+1
      else
           # Continue with 'mv' only if 'cp' worked
           mv -vf $i.stage $i >> $ARCHIVE_LOG 2>&1
           if [ $? -ne 0 ]; then
                let MV_INDICATOR=MV_INDICATOR+1
           fi
      fi
done

# End 'tar' processing log
echo -e "end file recovery error log on `date`\n" >> $ARCHIVE_LOG


#
# Rebuild the library search path based on the prior /etc/ld.so.conf
# information and then remove the temporary override path
#
if [ $PHMC -ne 0 ]; then
     # Temporarily relocate this directory prior to 'ldconfig' execution.  Appears
     # that 'ldconfig' will recurse into the /lib/i686 directory and there is a
     # potential for conflicting libraries residing in /lib.
#     mv -f /lib/i686/ /tmp/i686
     
     #
     # Turns out the for pHMC r41a release, which maps to particular kernel/RPM
     # versions, the *.so files in i686 directory shuold no longer exist.  Do not 
     # preserve them anymore, in fact remove them now! 10/08/03 - SLF
     #
     rm -fr /lib/i686
fi

/sbin/ldconfig -v >> $LOG 2>&1
/sbin/ldconfig /usr/X11R6/lib/
export LD_LIBRARY_PATH=

#
# Comment out i686 file manupulation. See prior comment above.  10/08/03
#
#if [ $PHMC -ne 0 ]; then
#     # Restore the i686 directory
#     mv -f /tmp/i686/ /lib/i686
#fi

#
# Cleanup any staged *.so files
#
rm -fr $WORKING_DIR


#
# Additional cleanup - there is the possibility that the directories under /home
# (all the users' dirs) may have been re-generated via this restore process.
# Unfortunately, if the directory itself was not part of the archive, it will
# have been created with uid/gid of root/root as part of un-taring the actual
# files in those directories. This is not good since the users will not be able
# to access their home dirs! Change ownership of those subdirectories to the
# corresponding userID.
#
cd /home/
for user in *
do
     if [ -d $user ]
     then
       g=`/usr/bin/id -g -n $user`
       chown $user.$g $user
       chmod 700 $user
       echo "chown/chmod of $user /home directory completed" >> $ARCHIVE_LOG
     fi
done
cd /

#
# What a surprise, more cleanup here. Turns out that older HMC drivers may not have
# certain font directories (/usr/X11R6/lib/x11/fonts/*, /usr/share/fonts/default/*)
# and their corresponding files installed. The backup script will archive the files
# in these directories if newer release HMC code is installed, but the directories
# themselves get re-generated by the 'tar' cmd with current date. Additionally, the
# 'xfs' init script does a -cnewer compare of every file in the corresonding font
# directory to the file 'fonts.dir'. If a "hit", then some font utility(s) get invoked
# which spews warning/error(?) messages to stdout during boot, which is disconcerning,
# but appears to have no ill effect.
#
# Simply re-touch the 'fonts.dir' file to its same date so this does not happen.
#
for d in $(/usr/sbin/chkfontpath --list | cut -f 2 -d ':') ;do
    if [ -d "$d" ]; then
         cd $d
         if [ "x$(find . -type f -cnewer fonts.dir 2>/dev/null)" != "x" ];then
             if [ -e fonts.dir ]; then
                 ls --full-time "$d/fonts.dir" | awk '{print "\""$10"-"$7"-"$8" " "$9"\""}' | xargs touch $d/fonts.dir -d $1
                 echo "'fonts.dir' file in, $d, re-touch'd" >> $ARCHIVE_LOG
             fi
         fi
    fi
done


#
# And yet more cleanup.  Check to see if there are duplicate 'startlangDialog' links
# in the run level scripts using different sequence numbers.  If so, remove them, and
# re-add it properly.
#
if [[ -L /etc/rc.d/rc5.d/S91startlangDialog && -L /etc/rc.d.rc5.d/S99startLangDialog ]]; then
    /sbin/chkconfig --del startlangDialog
    
    # assuming 'startlangDialog' is setup properly, we don't have to mess around with
    # setting the run level and start/kill link number
    /sbin/chkconfig --add startlangDialog
fi

 
#
# Another hack here - Assume this scenario: install r31 code, which conatins the
# file HwmcaCommon.jar.  'Efix' the  system to later HMC version which now uses
# the ccfw.jar replacement.  During this upgrade, some RPM did some cleanup during
# a post-install script which removed the old HwmcaCommon.jar file.  Now, if we
# do a backup at, say at the r41a driver level, we have only the ccfw.jar file and
# no HwmcaCommon.jar file.  Now re-install harddrive starting from the original
# r31 driver CD (system now contains the HwmcaCommon.jar file) and the restore script
# now executes and un-tar's the newer ccfw.jar file to it's proper place.  Now
# both files reside on the system and there is now a class conflict...naturally.
#
# If both HwmcaCommon and ccfw exist, simply trash the older HwmcaCommon file
#
if [[ -f /usr/websm/codebase/pluginjars/HwmcaCommon.jar && -f /opt/ccfw/ccfw.jar ]]; then
     echo -e "about to remove existing HwmcaCommon.jar file...\n" >> $LOG
     rm -fr /usr/websm/codebase/pluginjars/HwmcaCommon.jar
fi

#
# If there are both /opt/hsc/data/passwords and /opt/hsc/data/npwd
# Then must assume that the npwd will be the new one restored from the DVD
# and remove passwords to avoid incorrect migration of passwd to the new
# file
#
if [[ -f /opt/hsc/data/passwords && -f /opt/hsc/data/npwd ]]; then
   if [ /opt/hsc/data/passwords -ot /opt/hsc/data/npwd ]; then
      rm -fr /opt/hsc/data/passwords
   fi
fi
#
# Also remove the old restore log file, if it exists, since it has been
# renamed and isn't really valid once a new restore has run anyway...
#
if [ -f /var/hsc/log/hscrestore.log ]; then
     rm -f /var/hsc/log/hscrestore.log
fi


if [[ $CP_INDICATOR -eq 0 && $MV_INDICATOR -eq 0 ]]; then
     echo -e "\n restore exclude list files was successful, ARCHIVEFAIL is $ARCHIVEFAIL.\n" >> $LOG
   
     #----------------------------------------------------------------------------
     # remove the hmcConfigured if this is a new install
     # remove the indicator file
     #----------------------------------------------------------------------------
     if [ "$new_install" = "1" ]; then
          rm -f /opt/hsc/data/hmcConfigured
     fi
   
     rm -f $IQYBCRIT
     echo "restore indicator file removed from HMC" >> $LOG
else
     echo -e "\n restore from archive was NOT successful.\n" >> $LOG
     echo "cp indicator is: $CP_INDICATOR" >> $LOG
     echo -e "mv indicator is: $MV_INDICATOR\n" >> $LOG
   
     ARCHIVEFAIL=127
     umount -v $MOUNTPOINT >> $LOG 2>&1
     exit_cleanup 15
fi


#-------------------------------------------------------------------------------
# unmount the restore media
#-------------------------------------------------------------------------------
if umount -v $MOUNTPOINT >> $LOG 2>&1; then
     exit_cleanup 0
else
     echo "Couldn't umount the media" >> $LOG
     exit_cleanup 4
fi
